{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "-578TXDLZF47"
   },
   "outputs": [],
   "source": [
    "# Run this to install tensorflow version 1.9\n",
    "# !pip install tensorflow==1.9"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 51
    },
    "colab_type": "code",
    "id": "HnA-Zf8JqsL4",
    "outputId": "70062eee-0733-4f72-b717-2aeec3d927b9"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Gym: 0.10.11\n",
      "Tensorflow: 1.9.0\n"
     ]
    }
   ],
   "source": [
    "import gym\n",
    "import random\n",
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "from collections import deque\n",
    "print(\"Gym:\", gym.__version__)\n",
    "print(\"Tensorflow:\", tf.__version__)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "79GCjcYYqsMG"
   },
   "outputs": [],
   "source": [
    "class QNetwork():\n",
    "    def __init__(self, state_dim, action_size, tau=0.01):\n",
    "        tf.reset_default_graph()\n",
    "        self.state_in = tf.placeholder(tf.float32, shape=[None, *state_dim])\n",
    "        self.action_in = tf.placeholder(tf.int32, shape=[None])\n",
    "        self.q_target_in = tf.placeholder(tf.float32, shape=[None])\n",
    "        self.importance_in = tf.placeholder(tf.float32, shape=[None])\n",
    "        action_one_hot = tf.one_hot(self.action_in, depth=action_size)\n",
    "        \n",
    "        self.q_state_local = self.build_model(action_size, \"local\")\n",
    "        self.q_state_target = self.build_model(action_size, \"target\")\n",
    "        \n",
    "        self.q_state_action = tf.reduce_sum(tf.multiply(self.q_state_local, action_one_hot), axis=1)\n",
    "        self.error = self.q_state_action - self.q_target_in\n",
    "        self.loss = tf.reduce_mean(tf.multiply(tf.square(self.error), self.importance_in))\n",
    "        self.optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(self.loss)\n",
    "        \n",
    "        self.local_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope=\"local\")\n",
    "        self.target_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope=\"target\")\n",
    "        self.updater = tf.group([tf.assign(t, t + tau*(l-t)) for t,l in zip(self.target_vars, self.local_vars)])\n",
    "        \n",
    "    def build_model(self, action_size, scope):\n",
    "        with tf.variable_scope(scope):\n",
    "            hidden1 = tf.layers.dense(self.state_in, 100, activation=tf.nn.relu)\n",
    "            q_state = tf.layers.dense(hidden1, action_size, activation=None)\n",
    "            return q_state\n",
    "        \n",
    "    def update_model(self, session, state, action, q_target, importance):\n",
    "        feed = {self.state_in: state, self.action_in: action, self.q_target_in: q_target, self.importance_in: importance}\n",
    "        error, _, _ = session.run([self.error, self.optimizer, self.updater], feed_dict=feed)\n",
    "        return error\n",
    "        \n",
    "    def get_q_state(self, session, state, use_target=False):\n",
    "        q_state_op = self.q_state_target if use_target else self.q_state_local\n",
    "        q_state = session.run(q_state_op, feed_dict={self.state_in: state})\n",
    "        return q_state"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "EYKcRk3ZqsMJ"
   },
   "outputs": [],
   "source": [
    "class PrioritizedReplayBuffer():\n",
    "    def __init__(self, maxlen):\n",
    "        self.buffer = deque(maxlen=maxlen)\n",
    "        self.priorities = deque(maxlen=maxlen)\n",
    "        \n",
    "    def add(self, experience):\n",
    "        self.buffer.append(experience)\n",
    "        self.priorities.append(max(self.priorities, default=1))\n",
    "        \n",
    "    def get_probabilities(self, priority_scale):\n",
    "        scaled_priorities = np.array(self.priorities) ** priority_scale\n",
    "        sample_probabilities = scaled_priorities / sum(scaled_priorities)\n",
    "        return sample_probabilities\n",
    "    \n",
    "    def get_importance(self, probabilities):\n",
    "        importance = 1/len(self.buffer) * 1/probabilities\n",
    "        importance_normalized = importance / max(importance)\n",
    "        return importance_normalized\n",
    "        \n",
    "    def sample(self, batch_size, priority_scale=1.0):\n",
    "        sample_size = min(len(self.buffer), batch_size)\n",
    "        sample_probs = self.get_probabilities(priority_scale)\n",
    "        sample_indices = random.choices(range(len(self.buffer)), k=sample_size, weights=sample_probs)\n",
    "        samples = np.array(self.buffer)[sample_indices]\n",
    "        importance = self.get_importance(sample_probs[sample_indices])\n",
    "        return map(list, zip(*samples)), importance, sample_indices\n",
    "    \n",
    "    def set_priorities(self, indices, errors, offset=0.1):\n",
    "        for i,e in zip(indices, errors):\n",
    "            self.priorities[i] = abs(e) + offset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "XKIXlcQSqsMN"
   },
   "outputs": [],
   "source": [
    "class DoubleDQNAgent():\n",
    "    def __init__(self, env):\n",
    "        self.state_dim = env.observation_space.shape\n",
    "        self.action_size = env.action_space.n\n",
    "        self.q_network = QNetwork(self.state_dim, self.action_size)\n",
    "        self.replay_buffer = PrioritizedReplayBuffer(maxlen=100000)\n",
    "        self.gamma = 0.97\n",
    "        self.eps = 1.0\n",
    "        \n",
    "        self.sess = tf.Session()\n",
    "        self.sess.run(tf.global_variables_initializer())\n",
    "        \n",
    "    def get_action(self, state):\n",
    "        q_state = self.q_network.get_q_state(self.sess, [state])\n",
    "        action_greedy = np.argmax(q_state)\n",
    "        action_random = np.random.randint(self.action_size)\n",
    "        action = action_random if random.random() < self.eps else action_greedy\n",
    "        return action\n",
    "    \n",
    "    def get_env_action(self, action):\n",
    "        return action\n",
    "    \n",
    "    def train(self, state, action, next_state, reward, done, use_DDQN=True, a=0.0):\n",
    "        self.replay_buffer.add((state, action, next_state, reward, done))\n",
    "        (states, actions, next_states, rewards, dones), importance, indices = self.replay_buffer.sample(50, priority_scale=a)\n",
    "        \n",
    "        next_actions = np.argmax(self.q_network.get_q_state(self.sess, next_states, use_target=False), axis=1)\n",
    "        q_next_states = self.q_network.get_q_state(self.sess, next_states, use_target=use_DDQN)\n",
    "        q_next_states[dones] = np.zeros([self.action_size])\n",
    "        q_next_states_next_actions = q_next_states[np.arange(next_actions.shape[0]), next_actions]\n",
    "        q_targets = rewards + self.gamma * q_next_states_next_actions\n",
    "        errors = self.q_network.update_model(self.sess, states, actions, q_targets, importance**(1-self.eps))\n",
    "        \n",
    "        self.replay_buffer.set_priorities(indices, errors)\n",
    "        \n",
    "        if done: self.eps = max(0.1, 0.98*self.eps)\n",
    "    \n",
    "    def __del__(self):\n",
    "        self.sess.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "class DiscretizedDQNAgent(DoubleDQNAgent):\n",
    "    def __init__(self, env, n_actions=10):\n",
    "        self.is_discrete = type(env.action_space) == gym.spaces.discrete.Discrete\n",
    "        if not self.is_discrete:\n",
    "            env.action_space.n = n_actions\n",
    "            self.actions = np.linspace(env.action_space.low, env.action_space.high, n_actions)\n",
    "        super().__init__(env)\n",
    "        \n",
    "    def get_env_action(self, action):\n",
    "        if not self.is_discrete:\n",
    "            action = [self.actions[action]]\n",
    "        return action"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 51
    },
    "colab_type": "code",
    "id": "YHkYC1tmqsMB",
    "outputId": "c3abd168-27fc-4f2c-be25-18194375bd0d"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Observation space: Box(6,)\n",
      "Action space: Discrete(3)\n"
     ]
    }
   ],
   "source": [
    "env_names = [\"CartPole-v0\",\n",
    "             \"MountainCar-v0\",\n",
    "             \"MountainCarContinuous-v0\",\n",
    "             \"Pendulum-v0\",\n",
    "             \"Acrobot-v1\"]\n",
    "env = gym.make(env_names[4])\n",
    "print(\"Observation space:\", env.observation_space)\n",
    "print(\"Action space:\", env.action_space)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 187
    },
    "colab_type": "code",
    "id": "zv9Amjj4qsMQ",
    "outputId": "3e61344f-d87a-41e6-d28c-4ca3511ef4df"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Run 0\n",
      "Episode: 0, total_reward: -500.00\n",
      "Episode: 1, total_reward: -500.00\n",
      "Episode: 2, total_reward: -500.00\n",
      "Episode: 3, total_reward: -500.00\n",
      "Episode: 4, total_reward: -500.00\n",
      "Episode: 5, total_reward: -500.00\n",
      "Episode: 6, total_reward: -472.00\n",
      "Episode: 7, total_reward: -500.00\n",
      "Episode: 8, total_reward: -500.00\n",
      "Episode: 9, total_reward: -500.00\n",
      "Episode: 10, total_reward: -500.00\n",
      "Episode: 11, total_reward: -500.00\n",
      "Episode: 12, total_reward: -446.00\n",
      "Episode: 13, total_reward: -500.00\n",
      "Episode: 14, total_reward: -500.00\n",
      "Episode: 15, total_reward: -367.00\n",
      "Episode: 16, total_reward: -500.00\n",
      "Episode: 17, total_reward: -469.00\n",
      "Episode: 18, total_reward: -434.00\n",
      "Episode: 19, total_reward: -500.00\n",
      "Episode: 20, total_reward: -500.00\n",
      "Episode: 21, total_reward: -500.00\n",
      "Episode: 22, total_reward: -322.00\n",
      "Episode: 23, total_reward: -171.00\n",
      "Episode: 24, total_reward: -294.00\n",
      "Episode: 25, total_reward: -308.00\n",
      "Episode: 26, total_reward: -322.00\n",
      "Episode: 27, total_reward: -384.00\n",
      "Episode: 28, total_reward: -375.00\n",
      "Episode: 29, total_reward: -422.00\n",
      "Episode: 30, total_reward: -373.00\n",
      "Episode: 31, total_reward: -500.00\n",
      "Episode: 32, total_reward: -256.00\n",
      "Episode: 33, total_reward: -293.00\n",
      "Episode: 34, total_reward: -243.00\n",
      "Episode: 35, total_reward: -219.00\n",
      "Episode: 36, total_reward: -210.00\n",
      "Episode: 37, total_reward: -156.00\n",
      "Episode: 38, total_reward: -186.00\n",
      "Episode: 39, total_reward: -500.00\n",
      "Episode: 40, total_reward: -261.00\n",
      "Episode: 41, total_reward: -188.00\n",
      "Episode: 42, total_reward: -242.00\n",
      "Episode: 43, total_reward: -234.00\n",
      "Episode: 44, total_reward: -198.00\n",
      "Episode: 45, total_reward: -207.00\n",
      "Episode: 46, total_reward: -137.00\n",
      "Episode: 47, total_reward: -140.00\n",
      "Episode: 48, total_reward: -130.00\n",
      "Episode: 49, total_reward: -135.00\n",
      "Episode: 50, total_reward: -199.00\n",
      "Episode: 51, total_reward: -132.00\n",
      "Episode: 52, total_reward: -456.00\n",
      "Episode: 53, total_reward: -244.00\n",
      "Episode: 54, total_reward: -123.00\n",
      "Episode: 55, total_reward: -165.00\n",
      "Episode: 56, total_reward: -257.00\n",
      "Episode: 57, total_reward: -156.00\n",
      "Episode: 58, total_reward: -148.00\n",
      "Episode: 59, total_reward: -132.00\n",
      "Episode: 60, total_reward: -155.00\n",
      "Episode: 61, total_reward: -160.00\n",
      "Episode: 62, total_reward: -94.00\n",
      "Episode: 63, total_reward: -147.00\n",
      "Episode: 64, total_reward: -100.00\n",
      "Episode: 65, total_reward: -109.00\n",
      "Episode: 66, total_reward: -161.00\n",
      "Episode: 67, total_reward: -149.00\n",
      "Episode: 68, total_reward: -105.00\n",
      "Episode: 69, total_reward: -101.00\n",
      "Episode: 70, total_reward: -118.00\n",
      "Episode: 71, total_reward: -124.00\n",
      "Episode: 72, total_reward: -157.00\n",
      "Episode: 73, total_reward: -127.00\n",
      "Episode: 74, total_reward: -178.00\n",
      "Episode: 75, total_reward: -119.00\n",
      "Episode: 76, total_reward: -144.00\n",
      "Episode: 77, total_reward: -145.00\n",
      "Episode: 78, total_reward: -133.00\n",
      "Episode: 79, total_reward: -138.00\n",
      "Episode: 80, total_reward: -151.00\n",
      "Episode: 81, total_reward: -98.00\n",
      "Episode: 82, total_reward: -108.00\n",
      "Episode: 83, total_reward: -110.00\n",
      "Episode: 84, total_reward: -128.00\n",
      "Episode: 85, total_reward: -156.00\n",
      "Episode: 86, total_reward: -105.00\n",
      "Episode: 87, total_reward: -152.00\n",
      "Episode: 88, total_reward: -88.00\n",
      "Episode: 89, total_reward: -122.00\n",
      "Episode: 90, total_reward: -180.00\n",
      "Episode: 91, total_reward: -102.00\n",
      "Episode: 92, total_reward: -130.00\n",
      "Episode: 93, total_reward: -101.00\n",
      "Episode: 94, total_reward: -83.00\n",
      "Episode: 95, total_reward: -115.00\n",
      "Episode: 96, total_reward: -103.00\n",
      "Episode: 97, total_reward: -124.00\n",
      "Episode: 98, total_reward: -146.00\n",
      "Episode: 99, total_reward: -100.00\n"
     ]
    }
   ],
   "source": [
    "num_runs = 1\n",
    "run_rewards = []\n",
    "\n",
    "for n in range(num_runs):\n",
    "    print(\"Run {}\".format(n))\n",
    "    ep_rewards = []\n",
    "    agent = None\n",
    "    agent = DiscretizedDQNAgent(env)\n",
    "    num_episodes = 100\n",
    "\n",
    "    for ep in range(num_episodes):\n",
    "        state = env.reset()\n",
    "        total_reward = 0\n",
    "        done = False\n",
    "        while not done:\n",
    "            action = agent.get_action(state)\n",
    "            next_state, reward, done, info = env.step(agent.get_env_action(action))\n",
    "            agent.train(state, action, next_state, reward, done, a=0.7)\n",
    "            env.render()\n",
    "            total_reward += reward\n",
    "            state = next_state\n",
    "\n",
    "        ep_rewards.append(total_reward)\n",
    "        print(\"Episode: {}, total_reward: {:.2f}\".format(ep, total_reward))\n",
    "        \n",
    "    run_rewards.append(ep_rewards)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 311
    },
    "colab_type": "code",
    "id": "JU1OmrO0uHpO",
    "outputId": "d8cb4c76-6112-4327-f334-6e9669e0b990"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0xb249ce860>"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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kW5uId3eBqp4wmF848fjLS21FonJW15XHLnJZJsSijFm+6GqkEo5r6pOK6W5hUxrC5pOOzd6HDUKb3m5c8rLmC1kl7Mas4NSVTKtraTb2yGTcZJIOo0mkmgqCT37W8WDt7QUb3kZnkjERl6ZbWLJxZgdjGYyTl/J+g1oIu48q8TrRcQDXg+eojASKHNulSICIojX6/Sf2HNNzCDJK7mIyChAVbWpwPEYY7aSplKkmppINzaiySSeUAj/hAl4SkutFWKGXJ+9cyIyUUTuFZH1wGvAGyKyzi2rG6oAjTGbU1Uy0U7nosU1a0gsX07svfdJrV2LBAIEJk0iMGUK3rKyzRKLiHDmmWd2vU+lUlRXV3PCCScMepy33XYbq1YNfOnZj370I5599tkB13vyySepr69n2rRp7LHHHnznO98ZjDA3s3TpUmbOnMnUqVOZNWsWiYTdC3dL9Tf04z6cEV1jVHWqqu4KjAX+hnMXYrOdyMTjqP3n3yGpqjOCKx4n3d5OqrGRxIoG4u++S/yjD0muWtU1VNhbXkZw110JTp6Mt6Skz9ZKcXExixcvprOzE4BnnnmG2to+75q0TfJNLj/5yU845pj+r7tevHgxl1xyCXfddRfvvPMOixcvZpdddsk7llQqNfBKru9973tceumlfPDBB1RUVPCnP9kVDluqz4soReQD907DW7RspNhRLqJs+8c/WH3FlQR3352Jt/zJhopu57pdlPbk5bDmTQA0k0aTScgooF0XJPZ2MyMRwOtz+1I8Tp9J9gqTMXvDcT/rN4ZIJMI3vvEN9ttvP0499VTOOusspk+fzosvvshjjz1GY2Mj5513Hh999BFFRUXcdNNN7LPPPsyZM4dIJNLVWthrr7147LHHADjuuOM47LDDePnll6mtreXhhx/m8ccf55xzzqG2tpZwOMwrr7zCL37xCx599FE6Ozs55JBDuPHGGxERzjnnHE444QROPfVU6urqOPvss3n00UdJJpP85S9/YY899uCss87iyCOP5LzzztvsMz366KNcffXVJBIJKisrufvuuxk9ejRz5sxh1apVLFu2jKqqKu65555u/xZnn302r7/+OgDLli3jxBNP5N///jfV1dWsWbMGn8/HK6+8wpw5c3jqqafy/nfeUWzLRZT91UTzROQPIjJTRMa500wR+QPOxYpmGGU6Olh1xRU0XHwJ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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "for n, ep_rewards in enumerate(run_rewards):\n",
    "    x = range(len(ep_rewards))\n",
    "    cumsum = np.cumsum(ep_rewards)\n",
    "    avgs = [cumsum[ep]/(ep+1) if ep<100 else (cumsum[ep]-cumsum[ep-100])/100 for ep in x]\n",
    "    plt.plot(x, avgs, label=env_names[n])\n",
    "    \n",
    "plt.title(\"5 Environment performance\")\n",
    "plt.xlabel(\"Episode\")\n",
    "plt.ylabel(\"Last 100 episode average rewards\")\n",
    "plt.legend()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "_UBHQMHzqsMU"
   },
   "outputs": [],
   "source": [
    "env.close()"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "name": "PrioritizedExperienceReplayInOpenAIGym.ipynb",
   "provenance": [],
   "version": "0.3.2"
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
